/**
 * 用法一：断言后续流程无分支
 *    判断页面是否是期望页面
 *
 *    var elements = Jsoup.parse(html)
 *
 *    var isCorrectFunc = function(elements){
 *
 *        return condition
 *    }
 *
 *    var getErrorMsgFunc = function(elements) {
 *      return elements.select("xxxx").text()
 *    }
 *
 *    assertTrue(elements, isCorrectFunc, getErrorMsgFunc)
 *
 *    从json中获取结果
 *    var json = JSON.parse(jsonstr)
 *
 *    var isCorrectFunc = function(json){
 *
 *        return condition
 *    }
 *
 *    var getErrorMsgFunc = function(json) {
 *      return json.get("xxxx")
 *    }
 *
 *
 *
 * 用法二：断言后续流程有分支（暂不支持）
 *
 *    判断页面是否是期望页面
 *
 *    var forkFlagMappings = {
 *         "输入验证码"：[function() {
 *              // 1、等待用户输入
 *              // 2、输入并验证位数
 *              // 3、点击提交
 *              // 4、获取contentWillBeChecked
 *
 *              var isCorrectFunc = function(contentWillBeChecked) {
 *                   if(condition1){
 *                        context.put("forkFlag", "分支三")
 *                        return true
 *                   }
 *                   if(condition2){
 *                        context.put("forkFlag", "分支四")
 *                        return true
 *                   }
 *              }
 *              var getErrorMsgFunc = function(contentWillBeChecked) {
 *                  return getParamsFromContent.select("xxxx").text()
 *              }
 *              assertTrue(contentWillBeChecked, isCorrectFunc, getErrorMsgFunc)
 *         }],
 *         "无需验证码"：[function() {
 *              //xxxxxx
 *         }],
 *         "分支三" : [function(){}],
 *         "分支四" : [function(){}],
 *    }
 *    var contentWillBeChecked = Jsoup.parse(html)
 *
 *    var isCorrectFunc = function(contentWillBeChecked){
 *         if(condition1){
 *              context.put("forkFlag", "输入验证码")
 *              return true
 *         }
 *         if(condition2){
 *              context.put("forkFlag", "直接登录")
 *              return true
 *         }
 *    }
 *
 *    var getErrorMsgFunc = function(contentWillBeChecked) {
 *      return contentWillBeChecked.select("xxxx").text()
 *    }
 *
 *
 *    assertTrueAndExecuteNextFork(contentWillBeChecked, isCorrectFunc, getErrorMsgFunc)
 *
 *
 * @param contentWillBeChecked 待检查内容，可以是页面，可以是json 可以是Elements 等 可以是任何东西 取决于后三个函数的处理
 * @param isCorrectFunc 流程正确判断，遇到流程有分支时必须要在函数中设置分支标识forkFlag 以便于在forkMappings 取得处理函数
 * @param getErrorMsgFunc 用于获取错误信息
 */
function assertTrueOrThrowException(contentWillBeChecked, isCorrectFunc, getErrorMsgFunc) {
    if(!getErrorMsgFunc) {
        logger.error("任务【 {} 】 未定义getErrorMsgFunc函数", context.get(LUA_TASK_KEY))
        throw new BankException(BALO_99605_10, errorMsgMap.get(BALO_99605_10))
    }

    if (!assertTrue(contentWillBeChecked, isCorrectFunc)) {
        logger.error("任务【 {} 】当前节点校验未通过, 校验函数【 {} 】", context.get(LUA_TASK_KEY), isCorrectFunc)
        throwBankExceptionByErrorMsg(getErrorMsgFunc(contentWillBeChecked))
    }
    return true
}

var _context = {}
function repeater(contentWillBeCheckedFunc, isCorrectFunc, times, backFunc) {
    if(!contentWillBeCheckedFunc){
        logger.error("任务【 {} 】 未定义contentWillBeCheckedFunc函数", context.get(LUA_TASK_KEY));
        throw new BankException(BALO_99605_10, errorMsgMap.get(BALO_99605_10))
    }
    var flag = false;
    while(times > 0) {
        var contentWillBeChecked
        try {
            contentWillBeChecked = contentWillBeCheckedFunc()
        } catch(e) {
            contentWillBeChecked = null
        }
        _context['contentWillBeChecked'] = contentWillBeChecked
        flag = assertTrue(_context['contentWillBeChecked'], isCorrectFunc);
        if(flag) {
            break;
        }
        if(backFunc) {
            try {
                backFunc()
            } catch(e) {
                logger.error("任务【 {} 】 当前步骤后退出错,忽略错误", context.get(LUA_TASK_KEY))
            }
        }
        times--;
    }
    return flag;
}

function repeaterAndAssertTrueOrThrowException(contentWillBeCheckedFunc, isCorrectFunc, getErrorMsgFunc, times, backFunc){
    if(!repeater(contentWillBeCheckedFunc, isCorrectFunc, times, backFunc)){
        throwBankExceptionByErrorMsg(getErrorMsgFunc(_context['contentWillBeChecked']))
    }
    return true
}

function assertTrue(contentWillBeChecked, isCorrectFunc) {
    if(!isCorrectFunc) {
        logger.error("任务【 {} 】当前分支【 {} 】未定义isCorrectFunc函数", context.get(LUA_TASK_KEY), context.get("forkFlag"))
        throw new BankException(BALO_99605_10, errorMsgMap.get(BALO_99605_10))
    }
    return isCorrectFunc(contentWillBeChecked)
}


function assertTrueOrThrowExceptionByTimes(contentWillBeCheckedFunc, isCorrectFunc, getErrorMsgFunc,times) {
    if (!getErrorMsgFunc) {
        logger.error("任务【 {} 】 未定义getErrorMsgFunc函数", context.get(LUA_TASK_KEY));
        throw new BankException(BALO_99605_10, errorMsgMap.get(BALO_99605_10))
    }
    if(!contentWillBeCheckedFunc){
        logger.error("任务【 {} 】 未定义contentWillBeCheckedFunc函数", context.get(LUA_TASK_KEY));
        throw new BankException(BALO_99605_10, errorMsgMap.get(BALO_99605_10))
    }
    while(times>0) {
        var contentWillBeChecked = contentWillBeCheckedFunc();
        if (!assertTrue(contentWillBeChecked, isCorrectFunc)) {
            logger.error("任务【 {} 】当前节点校验未通过, 校验函数【 {} 】", context.get(LUA_TASK_KEY), isCorrectFunc)
            var errorMsg = getErrorMsgFunc(contentWillBeChecked);
            if(!errorMsg=="") {
                throwBankExceptionByErrorMsg(errorMsg);
            }
            if(errorMsg==""&&times==1){
                throwBankExceptionByErrorMsg("登录超时");
            }
        }else {
            break;
        }
        times--;
        Thread.sleep(1000);
    }
    return true
}

// function executeNextFork(){
//
//     if(context.get("forkFlag")) {
//         if(forkFlagMappings[context.get("forkFlag")].length === 2) {
//             forkFlagMappings[context.get("forkFlag")][1]()
//             logger.info("任务【 {} 】获取当前分支【 {} 】必要参数", context.get(LUA_TASK_KEY), context.get("forkFlag"))
//             var retVal = forkFlagMappings[context.get("forkFlag")][0]()
//             logger.info("任务【 {} 】执行当前分支【 {} 】成功", context.get(LUA_TASK_KEY), context.get("forkFlag"))
//             context.put("forkFlag", null)
//             logger.info("任务【 {} 】清空forkFlag标志", context.get(LUA_TASK_KEY), context.get("forkFlag"))
//             return retVal
//         } else {
//             logger.info("任务【 {} 】当前分支【 {} 】不需要获取参数即可进入下一步", context.get(LUA_TASK_KEY), context.get("forkFlag"))
//         }
//
//     }
// }

// /**
//  * 比assertTrue多了执行下一个分支的功能
//  *
//  * @param contentWillBeChecked
//  * @param isCorrectFunc
//  * @param getErrorMsgFunc
//  */
// function assertTrueAndExecuteNextFork(contentWillBeChecked, isCorrectFunc, getErrorMsgFunc){
//     assertTrue(contentWillBeChecked, isCorrectFunc, getErrorMsgFunc)
//     executeNextFork()
// }

/**
 * 根据错误描述抛异常
 *
 * @param errorMsg 官网返回的错误信息
 */
function throwBankExceptionByErrorMsg(errorMsg){

    var taskKey  = context.get(LUA_TASK_KEY)
    var bankName = context.get(LUA_TASK_BANK_NAME);
    var cardType = context.get(LUA_TASK_CARD_TYPE);
    var entrance = context.get("entrance")
    errorMsg = StringUtils.isNotBlank(errorMsg) ? StringUtils.trim(errorMsg): ""

    var errorCode = commonErrorMsgAndErrorCodeMappings[errorMsg]

    logger.error("任务【 {} 】银行名称【 {} 】 卡类型【 {} 】入口【 {} 】 错误信息：【 '{}' 】", taskKey, bankName, cardType, entrance, errorMsg)
    logger.error("任务【 {} 】【 commonErrorMsgAndErrorCodeMappings['{}'] = {} 】", taskKey, errorMsg, errorCode === undefined ? "undefined" : "'" + errorCode + "'")

    if(errorCode == null || errorCode === undefined) {
        var errorMsgMapping = bankCardTypeEntranceErrorMsgCategoryMappings[bankName][cardType][entrance]
        logger.error("任务【 {} 】【 bankCardTypeEntranceErrorMsgCategoryMappings['{}']['{}']['{}'] = {} 】",
            taskKey, bankName, cardType, entrance, errorMsgMapping === undefined ? "undefined" : "'" + errorMsgMapping + "'")
        if(errorMsgMapping == null || errorMsgMapping === undefined) {
            errorCode = context.get(PHASE) == null || context.get(PHASE).getStatus() < 352 ? BALO_23001_10 : BACR_99601_60
            throwBankExceptionByErrorCodeAndCustomMessage(errorCode, "请检查【 "+ bankName + " 】的错误描述映射配置是否正确，包括银行名称、卡类型、入口标识")
        }

        errorCode = errorMsgMapping[errorMsg]
        logger.error("任务【 {} 】【 bankCardTypeEntranceErrorMsgCategoryMappings['{}']['{}']['{}']['{}'] = {} 】",
            taskKey, bankName, cardType, entrance,  errorMsg, errorCode === undefined ? "undefined" : "'" + errorCode + "'")

        if(errorCode == null || errorCode === undefined) {
            errorCode = context.get(PHASE) == null || context.get(PHASE).getStatus() < 352 ? BALO_23001_10 : BACR_99601_60

        }
    }

    if (errorCode.contains("_")) {
        errorCode = errorCode.replaceAll("_", "-")
    }
    errorMsg = errorMsg !== null && errorMsg !== undefined ? errorMsg.trim() : errorMsgMap[errorCode]
    //“，请与银行联系”与BALO_99999_99的默认提示存在重复信息，因此替换
    if(errorMsg.contains("，请与银行联系")){
        errorMsg=errorMsg.replaceAll("，请与银行联系","");
    }

    //通用错误码，用来表示需要联系客服的情况
    if(equals(errorCode, BALO_99999_99)) {
        errorMsg = String.format(errorMsgMap[BALO_99999_99], errorMsg)
    }

    logger.error("任务【 {} 】本次抓取最终错误码与描述【 '{}:{}' 】", taskKey, errorCode, errorMsg)
    context.put("currentErrorCode", errorCode)
    throwBankExceptionByErrorCodeAndCustomMessage(errorCode, errorMsg)
}

/**
 * 根据错误码抛异常
 *
 * @param errorCode 错误码
 */
function throwBankExceptionByErrorCode(errorCode){
    throw new BankException(errorCode, errorMsgMap.get(errorCode))
}

/**
 * 根据错误码抛异常
 *
 * @param errorCode 错误码
 */
function throwBankExceptionByErrorCodeAndCustomMessage(errorCode, errorMsg){

    throw new BankException(errorCode, errorMsg)
}


//forkMappings 结构
//func1 代表这个分支的处理方法
//func2 代表获取func1处理方法所需要用到的参数

// var forkFlagMappings = {
//     "fork1" : [ forkHandler1, getParamsForForkHandler1],
//     "fork2" : [ forkHandler2, getParamsForForkHandler2],
// }